﻿/**
 * B3DScene
 * 
 * @author		Justen Holter
 * @version		1.0
 *
 */
package com.justenholter.basic3d {
	
	import com.justenholter.basic3d.cameras.B3DCamera;
	import com.justenholter.basic3d.objects.IRenderable;
	import flash.geom.Point
	import flash.utils.Dictionary;
	import flash.display.DisplayObject;
	
	public class B3DScene {
		
		public var scene	:Dictionary;
		public var vp		:Point;
		public var camera	:B3DCamera;
		public var zsorting	:Boolean;
		
		/**
		 * B3DScene
		 * 
		 * @param	vp			Point			vanishing point
		 * @param	camera		B3DCamera		camera
		 */
		public function B3DScene(vp:Point = null, camera:B3DCamera = null){
			this.vp = vp != null ? vp : new Point(0, 0);
			this.camera = camera != null ? camera : new B3DCamera();
			this.scene = new Dictionary(true);
			this.zsorting = true;
		}
		
		/**
		 * adds a object to the scene
		 * 
		 * @param	obj			IRenderable		object to add to scene
		 */
		public function add(obj:IRenderable):void {
			if(scene[obj] == null) scene[obj] = obj;
		}
		
		/**
		 * removes a object from the scene
		 * 
		 * @param	obj			IRenderable		object to remove from scene
		 */
		public function remove(obj:IRenderable):void {
			delete scene[obj];
		}
		
		/**
		 * render 2d positions based on x, y and z of all elements within the scene 
		 */
		public function render():void {
			
			//list of objects and there new z
			var zList:Array = new Array();
			
			//get camera rotation
			var radH:Number = camera.h * (Math.PI / 180);
			var sinH:Number = Math.sin(radH);
			var cosH:Number = Math.cos(radH);
			
			var radP:Number = camera.p * (Math.PI / 180);
			var sinP:Number = Math.sin(radP);
			var cosP:Number = Math.cos(radP);
			
			var radB:Number = camera.b * (Math.PI / 180);
			var sinB:Number = Math.sin(radB);
			var cosB:Number = Math.cos(radB);
			
			var obj:IRenderable, x:Number, y:Number, z:Number, scale:Number, newX:Number, newY:Number, newZ:Number;
			
			//render B3DSprites
			for(var i in scene){
				
				obj = scene[i];
				x = obj.x - camera.x;
				y = obj.y - camera.y;
				z = obj.z - camera.z;
				
				//rotate y by camera heading
				newX = sinH * z + cosH * x;
				newZ = cosH * z - sinH * x;
				x = newX; 
				z = newZ;
				
				//rotate x by camera pitch
				newY = cosP * y - sinP * z;
				newZ = sinP * y + cosP * z;
				y = newY;
				z = newZ;
				
				//rotate z by camera bank
				newX = cosB * x + sinB * y;
				newY = sinB * x - cosB * y;
				x = newX;
				y = newY;
				
				//get perspective
				scale = Math.max(0, camera.fl / (camera.fl + z));
				
				//add to zList for sorting
				zList.push({obj:obj, z:z});
				
				//render scale, x, y, and z to B3DSprite
				obj.render(this, scale, x, y, z);
			}
			
			if(zsorting == true){
				//zSorting
				zList.sortOn("z", Array.DESCENDING | Array.NUMERIC);
				for(var j:Number = 0; j < zList.length; j++){
					var dobj:DisplayObject = zList[j].obj as DisplayObject;
					if(dobj.parent != null) dobj.parent.setChildIndex(dobj, j);
				}
			}
		}
	}
}